package com.shinemo.mpush.alloc.handler;

import com.mpush.api.Constants;
import com.mpush.api.push.*;
import com.mpush.api.router.ClientLocation;
import com.mpush.tools.Jsons;
import com.mpush.tools.common.Strings;
import com.shinemo.mpush.alloc.domain.OfflineMsgVo;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by ThinkPad on 2017/9/25.
 */
public class MultiplePushHandler  implements HttpHandler {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private final PushSender pushSender = PushSender.create();
    private final AtomicInteger idSeq = new AtomicInteger();

    OfflineMsgHandler msgHandler = new OfflineMsgHandler();

    public void start() {
        pushSender.start();
    }

    public void stop() {
        pushSender.stop();
    }

    @SuppressWarnings("unchecked")
    @Override
    public void handle(HttpExchange httpExchange) throws IOException {
        String body = new String(readBody(httpExchange), Constants.UTF_8);
        Map<String, Object> params = Jsons.fromJson(body, Map.class);
        sendPush(params);
        byte[] data = "服务已经开始推送,请注意查收消息".getBytes(Constants.UTF_8);
        httpExchange.getResponseHeaders().set("Content-Type", "text/plain; charset=utf-8");
        httpExchange.sendResponseHeaders(200, data.length);//200, content-length
        OutputStream out = httpExchange.getResponseBody();
        out.write(data);
        out.close();
        httpExchange.close();
    }

    private void sendPush(Map<String, Object> params) {
        List<String> userList = (List<String>) params.get("users");
        Boolean broadcast = (Boolean) params.get("broadcast");
        String condition = (String) params.get("condition");
        OfflineMsgVo msgVo = msgHandler.setOfflineMsgVo(params);

        PushMsg pushMsg = PushMsg.build(MsgType.NOTIFICATION_AND_MESSAGE, Jsons.toJson(msgVo));
        pushMsg.setMsgId("msg_" + idSeq.incrementAndGet());

        pushSender.send(PushContext
                .build(pushMsg)
                .setUserIds(userList)
                .setBroadcast(broadcast != null && broadcast)
                .setCondition(Strings.isBlank(condition) ? null : condition)
                .setAckModel(AckModel.AUTO_ACK)
                .setCallback(new PushCallback() {
                    @Override
                    public void onResult(PushResult result) {
                        logger.info(result.toString());
                        switch (result.resultCode) {
                            case PushResult.CODE_SUCCESS:
                                onSuccess(result.userId, result.location);
                                break;
                            case PushResult.CODE_FAILURE:
                                onFailure(result.userId, result.location);
                                break;
                            case PushResult.CODE_OFFLINE:
                                onOffline(result.userId, result.location);
                                break;
                            case PushResult.CODE_TIMEOUT:
                                onTimeout(result.userId, result.location);
                                break;
                        }
                    }

                    /**
                     * 推送成功, 指定用户推送时重写此方法
                     *
                     * @param userId   成功的用户, 如果是广播, 值为空
                     * @param location 用户所在机器, 如果是广播, 值为空
                     */
                    public void onSuccess(String userId, ClientLocation location) {
                        //删除离线消息
                    }

                    /**
                     * 推送失败
                     *
                     * @param userId   推送用户
                     * @param location 用户所在机器
                     */
                    public void onFailure(String userId, ClientLocation location) {
                        System.out.println("用户：" + userId + "已经下线了");
                        List<String> userIds = new ArrayList<String>();
                        userIds.add(userId);
                        msgHandler.saveOfflineMsg(userIds, msgVo);
                    }

                    /**
                     * 推送用户不在线
                     *
                     * @param userId   推送用户
                     * @param location 用户所在机器
                     */
                    public void onOffline(String userId, ClientLocation location) {
                        System.out.println("用户：" + userId + "已经下线了");
                        List<String> userIds = new ArrayList<String>();
                        userIds.add(userId);
                        msgHandler.saveOfflineMsg(userIds, msgVo);
                    }

                    /**
                     * 推送超时
                     *
                     * @param userId   推送用户
                     * @param location 用户所在机器
                     */
                    public void onTimeout(String userId, ClientLocation location) {
                        System.out.println("用户：" + userId + "发送消息超时");
                        List<String> userIds = new ArrayList<String>();
                        userIds.add(userId);
                        msgHandler.saveOfflineMsg(userIds, msgVo);
                    }
                })
        );
    }

    private byte[] readBody(HttpExchange httpExchange) throws IOException {
        InputStream in = httpExchange.getRequestBody();
        String length = httpExchange.getRequestHeaders().getFirst("content-length");
        if (length != null && !length.equals("0")) {
            byte[] buffer = new byte[Integer.parseInt(length)];
            in.read(buffer);
            in.close();
            return buffer;
        } else {
            ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = in.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
            in.close();
            return out.toByteArray();
        }
    }
}
